# -*- encoding: utf-8 -*-
from sqlalchemy.orm import query
from flask import jsonify, request
from cc_flask.exception import ErrCode, RequiredParametersError


class RV:
    """ 请求校验（Request） """

    def __init__(self, describe=None, default=None, data_type=None):
        """
        实例化数据类
        :param describe:
        :param default:
        :param data_type:
        """
        self.describe = describe
        self.default = default
        self.data_type = data_type

    @property
    def to_dict(self):
        return {
            'describe': self.describe,
            'default': self.default,
            'data_type': self.data_type,
        }


class RRManage:
    """ 请求(Request)响应(Response)管理器 """
    to_dict = {}  # RRManage里所有的请求参数转为字典
    req_args = {}

    def __init__(self, *args, **kwargs):
        self.init_args(*args, **kwargs)

    def init_args(self, *args, **kwargs):
        """
        初始化参数，
        用法如下：
            # 请求带的参数：name="张三",age=null
            # 通过init_args()方法，传参args或者kwargs接收参数
            r = RRManage().init_args(name, age='年龄', sex=('性别', '未知'))

            print(r.name)  # 打印：张三，如果没有获取到前端传入的name，则返回None
            # 注意：默认值会在获取不到前端传参或者值为null的时候生效，效果如下
            print(r.age)  # 打印：18
            print(r.sex)  # 打印：未知

        :param args: 参数列表
        :param kwargs: 参数字典
        :return:
        """

        # {'default': '默认值', 'type': int, 'describe': '字段描述'}

        # 校验必填项
        self.args_verification(*args, **kwargs)

        # 初始化到类变量
        for k in args:
            if k.endswith('__'):
                k = k[:-2]
            _args = self.args.get(k)
            setattr(self, k, _args)

            if k in self.args.keys():
                self.req_args[k] = _args
            self.to_dict[k] = _args  # 填充to_dict

        for k, v in kwargs.items():

            if k.endswith('__'):
                k = k[:-2]
            _default = None
            _value = self.args.get(k)

            # 元组类型
            if isinstance(v, tuple):
                if len(v) > 1:  # 参数2：默认值
                    _default = v[1]
                if len(v) > 2:  # 参数3：指定类型
                    _value = v[2](_value)

            # RV类型
            if isinstance(v, RV):
                # name={'default': '匿名用户', 'type': str}
                _default = v.default
                _value = self.args.get(k)
                if v.data_type:
                    _value = v.data_type(_value)

            # 只有传参为None时才会用默认值，避免0，False等，也被用默认值
            setattr(self, k, _value if _value is not None else _default)

            self.to_dict[k] = _value
            if k in self.args.keys():
                self.req_args[k] = _value

        return self

    def args_verification(self, *args, **kwargs):
        """
        参数校验
        :return:
        """

        # _failed = [{
        #     'field': [],  # 字段
        #     'describe': [],  # 描述
        #     'field_des': [],  # 字段描述
        #     # 'type_error': [],
        # }]
        _failed = []
        for k in args:
            if not k.endswith('__'):
                continue

            k = k[:-2]
            if self.args.get(k) is not None:
                continue

            _failed.append({
                'field': k,
                'describe': k,
                'field_des': k
            })

        for k, v in kwargs.items():

            if not isinstance(v, (str, tuple, RV)):
                raise ValueError("参数错误：%s只接受（str、tuple、RV）类型，但得到%s" % (k, type(v)))

            if not k.endswith('__'):
                continue

            k = k[:-2]
            if self.args.get(k) is not None:
                continue

            if isinstance(v, str):
                msg = v
            elif isinstance(v, tuple) and len(v) >= 1:
                msg = v[0]
            elif isinstance(v, RV):
                msg = v.describe
            else:
                msg = k
            _failed.append({
                'field': k,
                'describe': msg,
                'field_des': "%s(%s)" % (k, msg)
            })

        if _failed:
            raise RequiredParametersError(
                '缺少必填参数：%s' % '、'.join([i['field_des'] for i in _failed]), _failed)

    @property
    def args(self):
        """
        获取请求数据，可以通过该方法直接获取，可以获取到查询参数、请求体（json格式）参数
        📢注意：如果传参是查询参数（也就是?后面的参数），所有类型都会被转换成str类型
        :return:
        """
        data = {}
        if request.method == "GET":
            return {**data, **(dict(request.args) or {})}
        return {**(dict(request.args) or {}), **(request.get_json(silent=True) or {})}

    # 输出json 成功信息
    def response_success(self, data=None, page=None, err_msg='ok', **kwargs):
        """ 成功响应 """
        return ResponseBase.base_json(data=data, page=page, err_msg=err_msg, **kwargs)

    # 输出json 失败信息
    def response_error(self, code, err_msg, data=None, err_cmsg=None):
        """ 失败响应 """
        return ResponseBase.base_json(code=code, err_msg=err_msg, err_cmsg=err_cmsg, data=data)

    def response_paginate(self, _query: query, err_msg='ok', err_cmsg=None,  **kwargs):
        """ 成功响应（结果分页） """
        _data, _page = self.paginate(_query)
        _data = [i.get_default() for i in _data]
        return ResponseBase.base_json(data=_data, page=_page, err_msg=err_msg, err_cmsg=err_cmsg,  **kwargs)

    def paginate(self, _query: query):
        """
        自定义分页
        :param _query: 需要分页的query，
        :return: 返回一个分页后转换后的结果
        """
        page = int(self.args.get("page") or 1)  # 当前页
        limit = int(self.args.get('limit') or 10)  # 每页数量

        paginate = _query.paginate(page=page, per_page=limit)
        page_dict = {
            "page": paginate.page,  # 当前分页
            "limit": paginate.per_page,  # 每页数量
            "total": paginate.total,  # 总数据量
            "page_count": paginate.pages,  # 总页数
        }
        return paginate.items, page_dict


def required_args(*args, **kwargs):
    """ 参数校验 """
    def decorator(func):
        def wrapper(*w_args, **w_kwargs):
            r = RRManage(*args, **kwargs)

            return func(r, *w_args, **w_kwargs)
        return wrapper
    return decorator


class ResponseBase:
    """ 响应基础结构 """

    @staticmethod
    def success(data=None, page=None, err_msg='ok'):
        """ 成功响应 """
        return ResponseBase.base_json(data=data, page=page, err_msg=err_msg)

    @staticmethod
    def error(code, err_msg, data=None, err_cmsg=None):
        """ 失败响应 """
        return ResponseBase.base_json(code=code, err_msg=err_msg, data=data, err_cmsg=err_cmsg)

    @staticmethod
    def base_json(code=ErrCode.OK, err_msg="ok", err_cmsg=None, data=None, page=None, **kwargs):
        """
        返回参数的基本结构
        :param code: 错误代码
        :param err_msg: 错误描述，给程序员看的，一般描述错误问题，方便排查问题。
        :param err_cmsg: 错误描述，用于展示给用户看的，站在客户的角度描述
        :param data: 响应的数据，字典、列表或None
        :param page: 分页器数据，包含当前页数、总页数、总数量、每页数量字段。字典类型或None， 为None时不分页
        :param kwargs: 其他字段补充
        :return:
        """
        return jsonify({
            'err_code': code,
            'err_msg': err_msg,
            'err_cmsg': err_cmsg,
            'data': data,
            'page': page,
            **kwargs
        })
